<?php

/**
 * JingYao-backend
 *
 * @link     https://gitee.com/wang-zhihui-release/jingyao-backend
 * @apiDocument https://gitee.com/wang-zhihui-release/jingyao-backend/wikis/
 */

namespace App\Services;

use App\Enums\AdminActionTypeEnum;
use App\Enums\AdminCheckEnum;
use App\Enums\AssessTemplateTypeEnum;
use App\Enums\CheckStatusEnum;
use App\Enums\CompanyStatusEnum;
use App\Enums\EnableStatusEnum;
use App\Events\CheckSuccess;
use App\Exceptions\ApiException;
use App\Format\CheckSuccessFormat;
use App\Format\CompanyAssessLogFormat;
use App\Format\CompanyFormat;
use App\Models\AssessTemplate;
use App\Models\AssessTemplateRule;
use App\Models\Company;
use App\Models\CompanyAssessLog;
use App\Models\UserProfile;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class CompanyService
{
    public function getAdminList(int $page, int $pageSize, array $search)
    {
        $builder = Company::query();
        if (isset($search['name'])) {
            $builder->where('name', 'like', '%' . $search['name'] . '%');
        }
        if (isset($search['check_status'])) {
            $builder->where('check_status', $search['check_status']);
        }
        $count = $builder->count();
        $list = $builder
            ->with([
                'assessLog' => function ($query) {
                    /* @var Builder $query */
                    $query->where('assess_time', '>=', strtotime(date('Y') . '-01-01'));
                    $query->where('assess_time', '<=', strtotime(date('Y') . '-12-31'));
                },
            ])
            ->orderBy('sort')
            ->skip(($page - 1) * $pageSize)
            ->take($pageSize)
            ->get()->toArray();
        foreach ($list as &$value) {
            $value['brief'] = trim(strip_tags($value['brief']));
        }
        return [
            'page' => $page,
            'page_size' => $pageSize,
            'count' => $count,
            'list' => $list,
        ];
    }

    public function getList(int $page, int $pageSize, array $search)
    {
        $builder = Company::query()->where('status', CompanyStatusEnum::SHOW)
            ->where('check_status', CheckStatusEnum::CHECK_ADOPT);
        if (isset($search['name'])) {
            $builder->where('name', 'like', '%' . $search['name'] . '%');
        }
        $count = $builder->count();
        $list = $builder
            ->orderBy('sort')
            ->skip(($page - 1) * $pageSize)
            ->take($pageSize)
            ->get()
            ->toArray();

        foreach ($list as &$value) {
            $value['brief'] = trim(strip_tags($value['brief']));
        }
        return [
            'page' => $page,
            'page_size' => $pageSize,
            'count' => $count,
            'list' => $list,
        ];
    }

    public function create(CompanyFormat $companyFormat)
    {
        $companyFormat->setPushTime(time());
        $companyFormat->setStatus(CompanyStatusEnum::SHOW);
        $companyFormat->setCheckStatus(CheckStatusEnum::CHECK_ADOPT);
        $companyName = $companyFormat->getName();
        if (Company::query()->where('name', $companyName)->exists()) {
            throw new ApiException('公司已存在', 1);
        }
        Company::query()->create($companyFormat->toArrayNotNull());
        adminLog(new Company(), AdminActionTypeEnum::CREATE, '创建公司');
        return true;
    }

    public function update(CompanyFormat $companyFormat)
    {
        $id = $companyFormat->getId();
        $company = Company::query()->find($id);
        if (empty($company)) {
            throw new ApiException('公司不存在', 1);
        }
        $companyFormat->setId(null);
        $company->update($companyFormat->toArrayNotNull());
        adminLog(new Company(), AdminActionTypeEnum::UPDATE, '修改公司信息');
        return true;
    }

    public function detail(int $id, $platform)
    {
        $company = Company::query()
            ->with([
                'assessLog',
                'assessLog.assessTemplate',
                'assessLog.assessTemplate.rules',
            ])
            ->find($id);
        if (empty($company)) {
            throw new ApiException('公司不存在', 1);
        }
        if ($platform == 'xcx') {
            // $company->brief = strip_tags($company->brief);
        }
        $assessLog = $company->assessLog;
        $res = $company->toArray();
        $res['assess_log'] = $this->groupAccess($assessLog->toArray());
        return $res;
    }

    public function setCompanyForCheck(CompanyFormat $companyFormat)
    {
        $companyFormat->setCheckStatus(CheckStatusEnum::CHECK_ING);
        $companyFormat->setStatus(CompanyStatusEnum::SHOW);
        $id = $companyFormat->getId();
        if (empty($id)) {
            if (Company::query()->where('name', $companyFormat->getName())->exists()) {
                throw new ApiException('公司已存在', 1);
            }
            $companyFormat->setPushTime(time());
            $companyFormat->setStatus(CompanyStatusEnum::SHOW);
            Company::query()->create($companyFormat->toArrayNotNull());
            return true;
        }
        $company = Company::query()->find($id);
        if (empty($company)) {
            throw new ApiException('公司不存在', 1);
        }
        $companyFormat->setId(null);
        $company->update($companyFormat->toArrayNotNull());
        return true;
    }

    public function checkCompany(int $id, int $checkStatus, string $checkMessage)
    {
        /** @var null|Company $company */
        $company = Company::query()->find($id);
        if (empty($company)) {
            throw new ApiException('公司不存在', 1);
        }
        $company->check_status = $checkStatus;
        $company->check_message = $checkMessage;
        $company->save();
        adminLog($company, AdminActionTypeEnum::UPDATE, '审核公司');
        event(new CheckSuccess(new CheckSuccessFormat([
            'check_status' => $checkStatus,
            'check_type' => AdminCheckEnum::CHECK_COMPANY,
            'user_id' => $company->register_user_id,
        ])));
        return true;
    }

    public function checkUser(int $userId)
    {
        return UserProfile::query()->where('user_id', $userId)
            ->where('check_status', CheckStatusEnum::CHECK_ADOPT)
            ->doesntHave('check')->exists();
    }

    public function getMyCompanies(int $userId)
    {
        /** @var null|UserProfile $userProfile */
        $userProfile = UserProfile::query()->where('user_id', $userId)
            ->where('check_status', CheckStatusEnum::CHECK_ADOPT)
            ->select('id_card_number')->first();
        if (empty($userProfile)) {
            Log::error('没有认证用户信息', [
                'user_id' => $userId,
            ]);
            return collect([]);
        }
        $userIdCardNumber = $userProfile->id_card_number;
        return Company::query()
            ->where('legal_person_id_card_number', $userIdCardNumber)
            ->get();
    }

    public function deleteCompany(int $id)
    {
        $company = Company::query()->find($id);
        if (empty($company)) {
            throw new ApiException('公司不存在', 1);
        }
        $company->delete();
        adminLog(new Company(), AdminActionTypeEnum::DELETE, '删除公司');
        return true;
    }

    public function assessCompany(CompanyAssessLogFormat $companyAssessLogFormat)
    {
        $tempId = $companyAssessLogFormat->getAssessTemplateId();
        if (! AssessTemplate::query()->where('id', $tempId)
            ->where('type', AssessTemplateTypeEnum::ASSESS_COMPANY)
            ->where('status', EnableStatusEnum::ENABLE)
            ->exists()) {
            throw new ApiException('模版不存在', 1);
        }
        $companyAssessLogFormat->setAssessTime(time());
        adminLog(new CompanyAssessLog(), AdminActionTypeEnum::CREATE, '考核企业');
        CompanyAssessLog::query()->create($companyAssessLogFormat->toArrayNotNull());
    }

    // 企业的考核记录
    public function companyAssessLogList(int $page, int $pageSize, int $userId, array $search)
    {
        $builder = CompanyAssessLog::query()->with('assessTemplate:type,title,name,id')
            ->groupBy('assess_template_id', 'company_id')
            ->select('company_id', 'assess_template_id', DB::raw('sum(score) as company_score'), DB::raw('max(assess_time) as push_time'));

        if (isset($search['company_name'])) {
            $companyIds = Company::query()
                ->where('')
                ->where('name', 'like', '%' . $search['company_name'] . '%')
                ->select('id')->get()->pluck('id')->toArray();
            $builder->whereIn('company_id', $companyIds);
        } else {
            $myCompanys = $this->getMyCompanies($userId);
            if ($myCompanys->count() < 1) {
                return [
                    'page' => $page,
                    'page_size' => $pageSize,
                    'count' => 0,
                    'list' => [],
                ];
            }
            $myCompanyIds = $myCompanys->pluck('id')->toArray();
            $builder->whereIn('company_id', $myCompanyIds);
        }

        $count = $builder->get()->count();

        $list = $builder->skip(($page - 1) * $pageSize)->take($pageSize)->get()->toArray();

        $companys = Company::query()->get()->toArray();
        $companyMap = array_column($companys, null, 'id');
        foreach ($list as &$value) {
            $value['company_name'] = $companyMap[$value['company_id']]['name'] ?? '';
            $value['push_time'] = date('Y-m-d H:i:s', $value['push_time']);
        }

        return [
            'page' => $page,
            'page_size' => $pageSize,
            'count' => $count,
            'list' => $list,
        ];
    }

    // 企业的某次考核详情
    public function getCompanyAssessDetail(int $companyId, int $assessTempId)
    {
        $logs = CompanyAssessLog::query()->where('company_id', $companyId)
            ->where('assess_template_id', $assessTempId)
            ->get();

        $ruleIds = $logs->pluck('assess_template_rule_id')->toArray();
        $rules = AssessTemplateRule::query()->whereIn('id', $ruleIds)->get()->toArray();
        $ruleMap = array_column($rules, null, 'id');
        $logs = $logs->toArray();
        foreach ($logs as &$log) {
            $ruleId = $log['assess_template_rule_id'];
            $log['item'] = $ruleMap[$ruleId]['item'];
            $log['rule'] = $ruleMap[$ruleId]['rule'];
            $log['score_explain'] = $ruleMap[$ruleId]['score_explain'];
        }

        return $logs;
    }

    public function setCompanySort(int $id, int $sort)
    {
        $company = Company::query()->where('id', $id)->first();
        $company->sort = $sort;
        adminLog($company, AdminActionTypeEnum::UPDATE, '修改企业排序');
        $company->save();
        return true;
    }

    private function groupAccess(array $assessLogs)
    {
        if (empty($assessLogs)) {
            return [];
        }
        $res = [];
        $ruleScoreMap = array_column($assessLogs, null, 'assess_template_rule_id');
        foreach ($assessLogs as $companyAccessLog) {
            $assessTemplate = $companyAccessLog['assess_template'];
            if (empty($assessTemplate)) {
                Log::error(sprintf('模版 id 【%s】 丢失', $companyAccessLog['assess_template_id']));
                return [];
            }
            if (checkArrayExistsInArray($res, $assessTemplate, 'id')) {
                continue;
            }
            $rules = $assessTemplate['rules'];
            foreach ($rules as &$rule) {
                $rule['score'] = $ruleScoreMap[$rule['id']]['score'] ?? 0;
            }
            $assessTemplate['rules'] = $rules;
            array_push($res, $assessTemplate);
        }
        return $res;
    }
}
